﻿using System;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Linq;

namespace KAKA
{
    public class Cryptography
    {
        private readonly byte[] _key;

        [DebuggerStepThrough]
        public Cryptography(string key)
        {
            _key = Encoding.UTF8.GetBytes(key);
        }

        [DebuggerStepThrough]
        public byte[] GenerateSalt()
        {
            byte[] buffer = new byte[16];

            using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
            using (SHA256 sha = new SHA256CryptoServiceProvider())
            {
                crypto.GetBytes(buffer);
                return sha.ComputeHash(buffer).Take(16).ToArray();
            }
        }

        [DebuggerStepThrough]
        public byte[] GeneratePassword(string password, byte[] salt)
        {
            byte[] buff = Encoding.UTF8.GetBytes(password);
            byte[] newBuff = new byte[buff.Length + salt.Length];

            buff.CopyTo(newBuff, 0);
            salt.CopyTo(newBuff, buff.Length);

            using (SHA256 sha = new SHA256CryptoServiceProvider())
            {
                return sha.ComputeHash(newBuff);
            }
        }

        [DebuggerStepThrough]
        public byte[] Encrypt(string plainText, byte[] salt)
        {
            var buff = Encoding.UTF8.GetBytes(plainText);

            using (Rijndael rijndael = Rijndael.Create())
            using (MemoryStream ms = new MemoryStream())
            using (CryptoStream cs = new CryptoStream(ms, rijndael.CreateEncryptor(_key, salt), CryptoStreamMode.Write))
            {
                cs.Write(buff, 0, buff.Length);
                cs.FlushFinalBlock();
                ms.Close();
                return ms.ToArray();
            }
        }

        [DebuggerStepThrough]
        public string Decrypt(byte[] buff, byte[] salt)
        {
            using (Rijndael rijndael = Rijndael.Create())
            using (MemoryStream ms = new MemoryStream(buff, 0, buff.Length))
            using (CryptoStream cs = new CryptoStream(ms, rijndael.CreateDecryptor(_key, salt), CryptoStreamMode.Read))
            using (StreamReader sr = new StreamReader(cs))
            {
                return sr.ReadToEnd();
            }
        }
    }
}